/*
 * Copyright 2004 original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.ayan.generic;

import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
 
 /**
  * This Class is a Generic Comparator Class,used for <b>Sorting Purpose<b>.
  * 1.It can sort any number of fields,any data type ..in any mode (ascending or descending).
  * 
  * @author Ayan Dutta  
  */
 
public class GComparator implements Comparator
{
    private  List<SortingFieldInfo> sortingFieldInfoList ; 
     
    /**
     * The constructor is made private to prevent its instantiation 
     * without the passing of SortingFieldInfo object list
     */
    private GComparator()
    {};
     
    /**
     * This constructor allows to pass the SortingFieldInfo object
     * list .
     * @param sortingFieldNameList
     */
    public GComparator(List<SortingFieldInfo> sortingFieldInfoList)
    {
        this.sortingFieldInfoList = sortingFieldInfoList;
    };
     
    /**
     * This is the main action point for any kind of sorting .
     * 
     */
    public int compare(Object obj1, Object obj2)
    {
        int flag = 0;
        try
        {
            if(sortingFieldInfoList!=null && sortingFieldInfoList.size() > 0)
            {
                Iterator<SortingFieldInfo> itr = sortingFieldInfoList.iterator();
                while(itr.hasNext())
                {
                    SortingFieldInfo sortingFieldInfoObj = itr.next();
                    flag = compareSingleField(obj1, obj2, sortingFieldInfoObj);
                    //Any return non-zero result will terminate the loop 
                    if(flag!=0)
                    {
                        break;
                    }
                }
            }
        }
        catch (Exception e) 
        {
            e.printStackTrace();
        }
        return flag;
    }
     
    /**
     * 
     * @param obj1
     * @param obj2
     * @param fieldNameToBeSorted
     * @param sortingMode
     * @return
     */
    public int compareSingleField(Object obj1, Object obj2,SortingFieldInfo sortingFieldInfoObj)
    {
        int flag = 0;
        try
        {
            // Get the actual field values using Java Reflection API
            Field field1 = obj1.getClass().getDeclaredField(sortingFieldInfoObj.getFieldNameToBeSorted());
            Field field2 = obj2.getClass().getDeclaredField(sortingFieldInfoObj.getFieldNameToBeSorted());
            field1.setAccessible(true);
            field2.setAccessible(true);
            if(field1 == null || field2==null)
            {
                return flag;
            }
            flag=((Comparable)field1.get(obj1)).compareTo(field2.get(obj2));
            //Check the sorting mode using checkMode method
            flag = checkMode(flag,sortingFieldInfoObj.getSortingMode());
        }
        catch (Exception e) 
        {
            e.printStackTrace();
        }
        return flag;
    }
     
    /**
     * This method determines the type of sorting .It can
     * 1.ascending (i.e. sortingMode is true).
     * 2.descending (i.e. sortingMode is false).
     * If sortingMode is false ,the output is just toggled
     * (i.e. 1 is made -1 and -1 is made 1).
     * @param flag
     * @param sortingMode
     * @return
     */
    private int checkMode (int flag,boolean sortingMode)
    {
        int finalValue = flag;
        /*
         * When the sorting mode is set for descending,just toggle the final result
         */
        if(sortingMode == false)
        {
            finalValue=finalValue*(-1);
        }
        return finalValue;
    }
}
